home *** CD-ROM | disk | FTP | other *** search
/ LiquidLibrary 2005 February / LiquidLibrary 2005 February - Disc 1.iso / pc / Portfolio Browser / Filters / PDF / LIB / pdfwrite.ps < prev   
Text File  |  2003-01-03  |  8KB  |  274 lines

  1. %    Copyright (C) 1999, 2000, 2001 Aladdin Enterprises.  All rights reserved.
  2. % This software is licensed to a single customer by Artifex Software Inc.
  3. % under the terms of a specific OEM agreement.
  4.  
  5. % $RCSfile$ $Revision$
  6. % Writer for transmuting PDF files.
  7.  
  8. % NOTES:
  9. % We do editing by replacing objects (in the cache) and then doing a
  10. %   simple recursive walk with object renumbering.
  11. % Free variables:
  12. %   RMap [per input file] (dict): input_obj# => output_obj#
  13. %   PDFfile (file): current input file
  14. %   OFile (file): current output file
  15. %   XRef (dict): output_obj# => output_file_pos
  16. %   ToWrite: 0..N-1 => [obj# gen#]
  17.  
  18. /.setlanguagelevel where { pop 2 .setlanguagelevel } if
  19. .currentglobal true .setglobal
  20.  
  21. /PDEBUG where { pop } { /PDEBUG false def } ifelse
  22.  
  23. % ================ Object mapping ================ %
  24.  
  25. % Initialize the object number and location map.
  26. /omapinit {        % - omapinit -
  27.   /RMap 100 dict def
  28.   /XRef 100 dict def
  29.   PDEBUG { (omapinit) = } if
  30. } def
  31.  
  32. % Map an object number.
  33. /omapnew {        % <oldobj#> omap <newobj#> <isnew>
  34.   RMap 1 index .knownget {
  35.     exch pop false
  36.   } {
  37.     PDEBUG { (omap\() print dup =only } if
  38.     RMap dup length 1 add 2 index exch dup 5 1 roll put pop true
  39.     PDEBUG { (\) = ) print 1 index = } if
  40.   } ifelse
  41. } def
  42. /omap {            % <oldobj#> omap <newobj#>
  43.   omapnew pop
  44. } bind def
  45.  
  46. % Save and restore the object map.
  47. % Note that currentomap either returns a copy or calls omapinit.
  48. /currentomap {        % <copy> currentomap <omap>
  49.   {
  50.     [RMap dup length dict copy XRef dup length dict copy]
  51.   } {
  52.     [RMap XRef] omapinit
  53.   } ifelse
  54. } bind def
  55. /setomap {        % <omap> setomap -
  56.   aload pop /XRef exch def /RMap exch def
  57.   PDEBUG {
  58.     (setomap: #Xref = ) print XRef length =only
  59.     (, #RMap = ) print RMap length =
  60.   } if
  61. } bind def
  62.  
  63. % ================ Writing ================ %
  64.  
  65. % ---------------- Low-level output ---------------- %
  66.  
  67. % Write a string on the output file.
  68. /ows {            % <string> ows -
  69.   OFile exch writestring
  70. } def
  71.  
  72. % ---------------- Scalars ---------------- %
  73.  
  74. % Note that the '#' character isn't legal in a name unless it is a prefix
  75. % for a hex encoded character (for PDF 1.2 and later). The following assumes
  76. % that the names are already valid PDF 1.2+ names so that  we can treat the
  77. % '#' as a legal character. The next two hex characters are already in the
  78. % set of valid name characters. PDF 1.1 and earlier allowed spaces in names
  79. % which probably wouldn't make it past the tokenizer anyway.
  80. /pdfnamechars
  81.   (!"#$&'*+,-.0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ\\^_`abcdefghijklmnopqrstuvwxyz|~)
  82. readonly def
  83. /pdfwritename {        % <name> pdfwritename -
  84.   (/) ows .namestring {
  85.     ( ) dup 0 4 -1 roll put
  86.     //pdfnamechars 1 index search {
  87.       pop pop pop
  88.     } {
  89.       pop 0 get 256 add 16 =string cvrs
  90.       dup 0 (#) 0 get put
  91.     } ifelse ows
  92.   } forall
  93. } def
  94.  
  95. % ---------------- Composite objects ---------------- %
  96.  
  97. /pdfwriteprocs mark
  98.   /resolveR { pdfwriteref }
  99.   /O { pdfwritenewref }
  100. .dicttomark readonly def
  101. /pdfwritearray {    % <array> pdfwritearray -
  102.   dup xcheck {
  103.     aload pop //pdfwriteprocs exch get exec
  104.   } {
  105.     % Because of a bug in Acrobat's parser for linearization parameters,
  106.     % we have to include some whitespace after the opening [ (!).
  107.     ([ ) ows { pdfwritevalue (\n) ows } forall (]) ows
  108.   } ifelse
  109. } def
  110.  
  111. /pdfwritedict {        % <dict> pdfwritedict -
  112.   dup xcheck {
  113.     pdfwritestream
  114.   } {
  115.     (<<) ows {
  116.       exch pdfwritevalue ( ) ows pdfwritevalue (\n) ows
  117.     } forall (>>) ows
  118.   } ifelse
  119. } def
  120.  
  121. % ---------------- References ---------------- %
  122.  
  123. /pdfwritenewref {    % <newobj#> pdfwritenewref -
  124.   OFile exch write=only ( 0 R) ows
  125. } def
  126.  
  127. /pdfwriteref {        % <obj#> <gen#> pdfwriteref -
  128.   1 index omapnew {
  129.     ToWrite dup length 5 -2 roll 2 packedarray put
  130.   } {
  131.     exch pop exch pop
  132.   } ifelse
  133.   pdfwritenewref
  134. } def
  135.  
  136. /pdfcopystring 200 string def
  137. /pdfwritestream {    % <streamdict> pdfwritestream -
  138.     % Remove File, FilePosition, and StreamKey;
  139.     % optimize by replacing an indirect Length.
  140.   dup dup length dict copy
  141.     % Stack: origdict dict
  142.   dup /File undef dup /FilePosition undef dup /StreamKey undef
  143.   dup /Length get dup oforce ne {
  144.     dup /Length 2 copy oget put
  145.   } if
  146.   exch dup /File get dup 3 -1 roll /FilePosition get setfileposition
  147.   pdfcopystream
  148. } def
  149.  
  150. % We put copying the stream contents in separate procedures so that we
  151. % can replace this function if desired.
  152. /pdfcopybytes {        % <fromfile> <tofile> <length> pdfcopybytes -
  153.   {
  154.     dup 0 eq { exit } if
  155.     //pdfcopystring 0 2 index 2 index length .min getinterval
  156.     3 index exch readstring 3 1 roll
  157.     3 index 1 index writestring length sub exch not { exit } if
  158.   } loop pop pop pop
  159. } def
  160. /pdfcopystream {    % <newstreamdict> <file> pdfcopystream -
  161.             %   (file has been positioned)
  162.   1 index pdfwritevalue (stream\n) ows
  163.   exch /Length get OFile exch pdfcopybytes
  164.   (endstream) ows
  165. } def
  166.  
  167. % ---------------- General values/objects ---------------- %
  168.  
  169. /pdfwritetypes mark
  170.     % Scalars
  171.   /nulltype { pop (null) ows }
  172.   /integertype { =string cvs ows }
  173.   /booleantype 1 index
  174.   /realtype { OFile exch write===only }
  175.   /stringtype 1 index
  176.   /nametype { pdfwritename }
  177.     % Composite/reference objects
  178.   /arraytype { pdfwritearray }
  179.   /packedarraytype 1 index
  180.   /dicttype { pdfwritedict }
  181. .dicttomark readonly def
  182.  
  183. /pdfwritevalue {    % <obj> pdfwritevalue -
  184.   PDEBUG { (****Writing: ) print dup === flush } if
  185.   //pdfwritetypes 1 index type get exec
  186. } def
  187.  
  188. % We make pdfwriteobjdef a separate procedure for external use.
  189. /pdfwriteobjheader {    % <newobj#> pdfwriteobjheader -
  190.   XRef 1 index OFile .fileposition put
  191.   PDEBUG { (XRef\() print dup =only (\) = ) print XRef 1 index get = } if
  192.   OFile exch write=only ( 0 obj\n) ows
  193. } def
  194. /pdfwriteobjdef {    % <newobj#> <value> pdfwriteobjdef -
  195.   exch pdfwriteobjheader
  196.   pdfwritevalue (\nendobj\n) ows
  197. } def
  198. /pdfwriteobj {        % <obj#> <gen#> pdfwriteobj -
  199.   1 index exch resolveR exch omap exch pdfwriteobjdef
  200. } def
  201.  
  202. % ---------------- File-level entities ---------------- %
  203.  
  204. % Write a PDF file header.
  205. % Free variables: OFile, PDFversion.
  206. /pdfwriteheader {    % - pdfwriteheader -
  207.   (%PDF-) ows OFile PDFversion write=
  208.   (%\347\363\317\323\n) ows
  209. } bind def
  210.  
  211. % Write a cross-reference table and trailer.
  212. /pdfwritexref {        % <firstobj#> <#objs> pdfwritexref -
  213.   (xref\n) ows
  214.   OFile 2 index write=only ( ) ows OFile 1 index write=
  215.   1 index add 1 sub 1 exch {
  216.     dup 0 eq {
  217.       pop (0000000000 65535 f \n) ows
  218.     } {
  219.       XRef exch get 1000000000 add =string cvs
  220.       dup 0 (0) 0 get put
  221.       ows ( 00000 n \n) ows
  222.     } ifelse
  223.   } for
  224. } bind def
  225. /pdfwritetrailer {    % <trailer> pdfwritetrailer -
  226.   (trailer\n) ows pdfwritevalue (\n) ows
  227. } bind def
  228. /pdfwritestartxref {    % <startpos> pdfwritestartxref -
  229.   (startxref\n) ows OFile exch write=
  230.   (%%EOF\n) ows
  231. } bind def
  232.  
  233. % ================ Top-level control ================ %
  234.  
  235. /pdfwrite {        % <file> <trailer> pdfwrite -
  236.   10 dict begin
  237.   /trailer exch def
  238.   /OFile exch def
  239.   /ToWrite 100 dict def
  240.   omapinit
  241.  
  242.     % Write the PDF file header.
  243.  
  244.   pdfwriteheader
  245.  
  246.     % Write the objects.
  247.  
  248.   trailer {
  249.     exch pop dup xcheck {    % The only executable objects are references.
  250.       aload pop pop pdfwriteobj
  251.     } {
  252.       pop
  253.     } ifelse
  254.   } forall
  255.     % Walk the object graph.
  256.   {
  257.     ToWrite dup length dup 0 eq { pop pop exit } if
  258.     1 sub 2 copy get 3 1 roll undef aload pop pdfwriteobj
  259.   } loop
  260.  
  261.     % Write the xref table and trailer.
  262.  
  263.   /xref OFile fileposition def
  264.   0 XRef length 1 add pdfwritexref
  265.   trailer dup length 1 add dict copy
  266.   dup /Size XRef length 1 add put pdfwritetrailer
  267.   xref pdfwritestartxref
  268.  
  269.   end
  270. } def
  271.  
  272. .setglobal
  273.